package com.xlf.service.judge.strategy.judgeMachine.impl.goJudge.builder;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.xlf.common.core.util.StringUtils;
import com.xlf.service.judge.io.File;
import com.xlf.service.judge.io.impl.LocalFile;
import com.xlf.service.judge.io.impl.StringFile;
import com.xlf.service.judge.pojo.RunLimit;

import java.util.List;
import java.util.Map;

/**
 * @Author xlf 2734029211@qq.com
 * @Date 2023/9/15 23:35
 * @Description: TODO
 * @Version 1.0
 */
public class RunCmdBuilder extends CmdBuilder{

    /**
     * 执行命令
     */
    private List<String> args;

    /**
     * 环境变量
     */
    private List<String> env;

    /**
     * 控制台默认输入
     */
    private File content;

    //------------沙箱环境限制-----------
    //cpu时间片限制 单位 ms
    private Long cpuLimit = 1000L;

    //内存限制 单位b 默认256mb
    private Long memoryLimit = 104857600L;

    // 等待时间限制，单位纳秒 （通常为 cpuLimit 两倍）
    private Long clockLimit = 10000L;

    //栈空间限制 单位b
    private Long stackLimit = 10000L;

    //最大线程限制
    private Long procLimit = 128L;


//------------------------------------
    /**
     * 需要输入的文件
     * key：文件名称
     * value:文件内容
     * eg ： a.cc : "#include <iostream>\nusing namespace std;\nint main() {\nint a, b;\ncin >> a >> b;\ncout << a + b << endl;\n}"
     */
    private Map<String,String> copyIn;

    /**
     * 指定需要导出的文件数组 eg: ["stdout", "stderr"],这2个是代码执行结果输出和错误输出
     * 以内容的形式返回
     * return  eg: "files": {
     *             "stderr": "",
     *             "stdout": ""
     *         },
     */
    private List<String> copyOut;

    /**
     * 指定需要导出的文件数组  eg :["a","a.cc"]
     * 以fileId的形式返回
     *  return  eg:   "fileIds": {
     *             "a": "VCAIK2F4",
     *             "a.cc": "U37JLAW3"
     *         }
     */
    private List<String> copyOutCached;


    /**
     *
     * @param args              编译的cmd参数
     * @param envs              编译的环境变量
     * @param copyIn            输入的文件
     * @param copyOutCached     输出的文件
     * @param consoleInput      控制台输入
     */
    public RunCmdBuilder(List<String> args,
                             List<String> envs,
                             RunLimit runLimit,
                             Map<String,String> copyIn,
                             File consoleInput,
                             List<String> copyOutCached
    ){
        this.args = args;
        this.env = envs;
        this.copyIn = copyIn;
        this.content = consoleInput;
        this.copyOutCached  = copyOutCached;
        this.memoryLimit = runLimit.getMaxMemory() * 1024L;
        this.stackLimit = runLimit.getMaxStack() * 1024L;
        this.cpuLimit = runLimit.getMaxTime() * 1L;
    }


    @Override
    public void buildArgs() {
        cmd.put("args", args);

    }

    @Override
    public void buildEnv() {
        cmd.put("env", env);

    }

    /**
     * return :
     *    "files": [{
     *             "content": ""
     *         }, {
     *             "name": "stdout",
     *             "max": 10240
     *         }, {
     *             "name": "stderr",
     *             "max": 10240
     *         }],
     */
    public void buildFiles(){

        JSONArray files = new JSONArray();
        JSONObject content = new JSONObject();

        if(this.content == null)
            content.put("content", "");
        else {
            if(this.content instanceof StringFile)
                content.put("content", this.content.value());
            else if(this.content instanceof LocalFile)
                content.put("src",this.content.value());
            else
                content.put("fileId",this.content.value());
        }

        JSONObject stdout = new JSONObject();
        stdout.put("name", "stdout");
        stdout.put("max", 1024 * 1024 * 32);

        JSONObject stderr = new JSONObject();
        stderr.put("name", "stderr");
        stderr.put("max", 1024 * 1024 * 32);
        files.add(content);
        files.add(stdout);
        files.add(stderr);

        cmd.put("files",files);
    }

    @Override
    public void buildCpuLimit() {
        // ms-->ns
        cmd.put("cpuLimit", (cpuLimit + 200) * 1000 * 1000L);
        // byte
    }

    @Override
    public void buildMemoryLimit() {
        cmd.put("memoryLimit", memoryLimit);

    }

    @Override
    public void buildClockLimit() {
        cmd.put("clockLimit", 2 * cpuLimit * 1000 * 1000L);
    }

    @Override
    public void buildStackLimit() {
        cmd.put("stackLimit", stackLimit);
    }

    @Override
    public void buildProcLimit() {
        cmd.put("procLimit", procLimit);

    }

    /**
     * return rg:
     *   "copyIn": {
     *             "a.cc": {
     *                 "content": "#include <iostream>\nusing namespace std;\nint main() {\nint a, b;\ncin >> a >> b;\ncout << a + b << endl;\n}"
     *             }
     *         },
     */
    @Override
    public void buildCopyIn() {
        JSONObject copyIn_ = new JSONObject();
        if(StringUtils.isNotEmpty(copyIn)){
            for (Map.Entry<String, String> entry : copyIn.entrySet()) {
                if (!StringUtils.isEmpty(entry.getKey()) && !StringUtils.isEmpty(entry.getValue())) {
                    JSONObject content = new JSONObject();
                    content.put("fileId", entry.getValue());
                    copyIn_.put(entry.getKey(), content);
                }
            }
        }
        cmd.put("copyIn",copyIn_);
    }

    /**
     * eg: "copyOut": ["stdout", "stderr", ....],
     */
    @Override
    public void buildCopyOut() {
        JSONArray jsonArray = new JSONArray();
        jsonArray.add("stdout");
        jsonArray.add("stderr");
        if(StringUtils.isNotEmpty(copyOut)){
            jsonArray.addAll(copyOut);
        }
        cmd.put("copyOut", jsonArray);

    }

    /**
     * eg "copyOutCached": [..,...,....]
     */
    @Override
    public void buildCopyOutCached() {
        JSONArray jsonArray = new JSONArray();
        if(StringUtils.isNotEmpty(copyOutCached)){
            jsonArray.addAll(copyOutCached);
        }
        cmd.put("copyOutCached", jsonArray);
    }


}
